﻿using System.Globalization;
using System.Runtime.InteropServices;

namespace Microsoft.Xna.Framework.Input
{
    /// <summary>
    /// Represents the state of a mouse input device, including mouse cursor position and buttons pressed.
    /// </summary>
	[StructLayout(LayoutKind.Sequential)]
    public struct MouseState
	{
		#region Fields
		int x;
        int y;
        ButtonState left;
		ButtonState middle;
        ButtonState right;
		int scrollWheelValue;
		ButtonState xButton1;
		ButtonState xButton2;
		#endregion

		#region Properties
		/// <summary>
		/// Returns the state of the left mouse button.
		/// </summary>
		public ButtonState LeftButton
		{
			get { return left; }
			internal set { left = value; }
		}

		/// <summary>
		/// Returns the state of the middle mouse button.
		/// </summary>
		public ButtonState MiddleButton
		{
			get { return middle; }
			internal set { middle = value; }
		}

		/// <summary>
		/// Returns the state of the right mouse button.
		/// </summary>
		public ButtonState RightButton
		{
			get { return right; }
			internal set { right = value; }
		}

		/// <summary>
		/// Gets the cumulative mouse scroll wheel value since the game was started.
		/// </summary>
		public int ScrollWheelValue
		{
			get { return scrollWheelValue; }
			internal set { scrollWheelValue = value; }
		}

		/// <summary>
		/// Specifies the horizontal position of the mouse cursor.
		/// </summary>
		public int X
		{
			get { return x; }
			internal set { x = value; }
		}

		/// <summary>
		/// Returns the state of XBUTTON1.
		/// </summary>
		public ButtonState XButton1
		{
			get { return xButton1; }
			internal set { xButton1 = value; }
		}

		/// <summary>
		/// Returns the state of XBUTTON2.
		/// </summary>
		public ButtonState XButton2
		{
			get { return xButton2; }
			internal set { xButton2 = value; }
		}

		/// <summary>
		/// Specifies the vertical position of the mouse cursor.
		/// </summary>
		public int Y
		{
			get { return y; }
			internal set { y = value; }
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Initializes a new instance of the MouseState class.
		/// </summary>
		/// <param name="x">Horizontal mouse position.</param>
		/// <param name="y">Vertical mouse position.</param>
		/// <param name="scrollWheel">Mouse scroll wheel value.</param>
		/// <param name="leftButton">Left mouse button state.</param>
		/// <param name="middleButton">Middle mouse button state.</param>
		/// <param name="rightButton">Right mouse button state.</param>
		/// <param name="xButton1">XBUTTON1 state.</param>
		/// <param name="xButton2">XBUTTON2 state.</param>
		public MouseState(int x, int y, int scrollWheel, ButtonState leftButton, ButtonState middleButton, ButtonState rightButton, ButtonState xButton1, ButtonState xButton2)
		{
			this.x = x;
			this.y = y;
			this.left = leftButton;
			this.middle = middleButton;
			this.right = rightButton;
			this.scrollWheelValue = scrollWheel;
			this.xButton1 = xButton1;
			this.xButton2 = xButton2;
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Returns a value that indicates whether the current instance is equal to a specified object.
		/// </summary>
		/// <param name="obj">Object with which to make the comparison.</param>
		/// <returns>true if the specified object is equal to this instance; otherwise, false.</returns>
		public override bool Equals(object obj)
		{
			if (obj is MouseState)
				return this == (MouseState)obj;
			return false;
		}

		/// <summary>
		/// Gets the hash code for this instance.
		/// </summary>
		public override int GetHashCode()
		{
			return (((((((this.x.GetHashCode() ^ this.y.GetHashCode()) ^ this.left.GetHashCode()) ^ this.right.GetHashCode()) ^ this.middle.GetHashCode()) ^ this.xButton1.GetHashCode()) ^ this.xButton2.GetHashCode()) ^ this.scrollWheelValue.GetHashCode());
		}

		/// <summary>
		/// Retrieves a string representation of this object.
		/// </summary>
		public override string ToString()
		{
			string str = string.Empty;
			if (this.left == ButtonState.Pressed)
			{
				str = str + (string.IsNullOrEmpty(str) ? "" : " ") + "Left";
			}
			if (this.right == ButtonState.Pressed)
			{
				str = str + (string.IsNullOrEmpty(str) ? "" : " ") + "Right";
			}
			if (this.middle == ButtonState.Pressed)
			{
				str = str + (string.IsNullOrEmpty(str) ? "" : " ") + "Middle";
			}
			if (this.xButton1 == ButtonState.Pressed)
			{
				str = str + (string.IsNullOrEmpty(str) ? "" : " ") + "XButton1";
			}
			if (this.xButton2 == ButtonState.Pressed)
			{
				str = str + (string.IsNullOrEmpty(str) ? "" : " ") + "XButton2";
			}
			if (string.IsNullOrEmpty(str))
			{
				str = "None";
			}
			return string.Format(CultureInfo.CurrentCulture, "{{X:{0} Y:{1} Buttons:{2} Wheel:{3}}}", new object[] { this.x, this.y, str, this.scrollWheelValue });
		}
		#endregion

		#region Operators
		/// <summary>
		/// Determines whether two MouseState instances are not equal.
		/// </summary>
		/// <param name="left">Object on the left of the inequality sign.</param>
		/// <param name="right">Object on the right of the inequality sign.</param>
		/// <returns>true if the object are not equal; otherwise, false.</returns>
		public static bool operator !=(MouseState left, MouseState right)
		{
			return ((left.left != right.left) || (left.middle != right.middle) ||
					(left.right != right.right) || (left.scrollWheelValue != right.scrollWheelValue) ||
					(left.x != right.x) || (left.xButton1 != right.xButton1) ||
					(left.xButton2 != right.xButton2) || (left.y != right.y));
		}

		/// <summary>
		/// Determines whether two MouseState instances are equal.
		/// </summary>
		/// <param name="left">Object on the left of the equality sign.</param>
		/// <param name="right">Object on the right of the equality sign.</param>
		/// <returns>true if both objects are equal; otherwise, false.</returns>
		public static bool operator ==(MouseState left, MouseState right)
		{
			return ((left.left == right.left) && (left.middle == right.middle) &&
					(left.right == right.right) && (left.scrollWheelValue == right.scrollWheelValue) &&
					(left.x == right.x) && (left.xButton1 == right.xButton1) &&
					(left.xButton2 == right.xButton2) && (left.y == right.y));
		}
		#endregion
	}
}
